package com.cnpc.netty.transfer;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.unix.Buffer;
import io.netty.handler.codec.MessageToMessageDecoder;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class Transfer {
	private static final char[] CHARS_TABLES = "0123456789ABCDEF".toCharArray();
	public static int udpport;
	public static String tcpip;
	public static int tcpport;
	static Bootstrap boot;
	static EventLoopGroup group;

	static EventLoopGroup tcpGroup;
	static Bootstrap tcpBoot;
	static Channel udpc;
	static Channel tcpc;

	static UdpSender udpSender;

	public Transfer(UdpSender udpSender, Integer udpport, String tcpip, Integer tcpport) {
		Transfer.udpSender = udpSender;
		Transfer.udpport = udpport;
		Transfer.tcpip = tcpip;
		Transfer.tcpport = tcpport;
	}

	public void close() {
		Transfer.udpc.close();
		Transfer.tcpc.close();
	}

	public void start() {
		group = new NioEventLoopGroup();
		boot = new Bootstrap();

		boot.group(group)
				.channel(NioDatagramChannel.class)
				.option(ChannelOption.SO_BROADCAST, Boolean.TRUE)
				.option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
				.handler(getInitHandle())
				.handler(getDataDecoder())
				.handler(getDataHandler());

		ChannelFuture cf = boot.bind(udpport).awaitUninterruptibly();
		udpc = cf.channel();
		try {
			cf.get();
		} catch (Exception e) {
			e.printStackTrace();
		}

		TcpConnection tcpConnection = new TcpConnection();
		tcpConnection.connect(Transfer.tcpip, Transfer.tcpport);


//		EventLoopGroup tcpGroup = new NioEventLoopGroup();
//		tcpBoot = new Bootstrap();
//		try {
//			tcpBoot.group(tcpGroup).channel(NioSocketChannel.class).handler(
//					new ChannelInitializer() {
//						protected void initChannel(Channel arg0) {
//							ChannelPipeline pipeline = arg0.pipeline();
//							pipeline.addLast("decoder", new ByteArrayDecoder());
//							pipeline.addLast("encoder", new ByteArrayEncoder());
//						}
//					}
//			);
//			// 设置TCP协议的属性
//			tcpBoot.option(ChannelOption.SO_KEEPALIVE, true);
//			tcpBoot.option(ChannelOption.TCP_NODELAY, true);
//			tcpBoot.option(ChannelOption.SO_TIMEOUT, 5000);
//
//			Transfer.tcpc = Transfer.tcpBoot.connect(Transfer.tcpip, Transfer.tcpport).sync().channel();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}

	}

	public InitHandle getInitHandle() {
		return new InitHandle();
	}

	public DataHandler getDataHandler() {
		return new DataHandler();
	}

	public DataDecoder getDataDecoder() {
		return new DataDecoder();
	}

	public static class DataDecoder extends MessageToMessageDecoder<DatagramPacket> {
		public DataDecoder() {
		}

		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
			System.out.println("Transfer run decoder exceptionCaught");
			super.exceptionCaught(ctx, cause);
		}

		protected void decode(ChannelHandlerContext arg0, DatagramPacket arg1, List<Object> arg2) throws Exception {
			System.out.println(arg1.toString() + "dec");
		}
	}

	public static class DataHandler extends SimpleChannelInboundHandler<String> {
		public DataHandler() {
		}

		protected void channelRead0(ChannelHandlerContext arg0, String arg1) throws Exception {
			System.out.println("Transfer run handle read0  " + arg1);
		}

		public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
			DatagramPacket packet = (DatagramPacket) msg;
			ByteBuf byteBuf = packet.content();
			ByteBuffer byteBuffer = null;
			byte cmd = byteBuf.readByte();
			if(cmd == 0x30){
				byte code = byteBuf.readByte();
				int length = byteBuf.readInt();
				byte[] body = new byte[length - 6];
				byteBuf.readBytes(body,0, length - 6);
				byteBuffer = ByteBuffer.allocate(length);
				byteBuffer.putInt(length).put(cmd).put(code).put(body);
				System.out.println("Transfer run handle channelRead byteBuffer = " + toHexString(byteBuffer.array()));
			}else if((cmd == 0x10)||(cmd == 0x20)) {
				byte code = byteBuf.readByte();
				int length = byteBuf.readShort();
				byte[] body = new byte[length - 4];
				byteBuf.readBytes(body,0, length - 4);
				byteBuffer = ByteBuffer.allocate(length + 2);
				byteBuffer.putInt(length).put(cmd).put(code).put(body);
				System.out.println("Transfer run handle channelRead byteBuffer = " + toHexString(byteBuffer.array()));
			}else {
				Transfer.udpSender.stop();
				return;
			}


			//Transfer.tcpc ==null 说明TCP client未启动，直接不往TCP写入包，丢弃此包 （可优化用其他方式判断，目前这样没问题）
			if(Transfer.tcpc != null){
				//Random random = new Random();
				// 生成一个随机整数，范围在0（包含）和10（不包含）之间
				//int randomInt = random.nextInt(10);
				//if(randomInt == 5) {
					Transfer.tcpc.writeAndFlush(byteBuffer.array());
				//}
			}
			
			//Transfer.tcpc.close();
			super.channelRead(ctx, msg);
		}

		public void channelActive(ChannelHandlerContext ctx) throws Exception {
			System.out.println("Transfer run handle channelActive");
			super.channelActive(ctx);
		}

		public void channelInactive(ChannelHandlerContext ctx) throws Exception {
			System.out.println("Transfer run handle channelInactive");
			super.channelInactive(ctx);
		}

		public boolean acceptInboundMessage(Object msg) throws Exception {
			//System.out.println("Transfer run handle acceptInboundMessage msg = " + msg.toString());
			return super.acceptInboundMessage(msg);
		}

		public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
			//System.out.println("Transfer run handle channelReadComplete");
			super.channelReadComplete(ctx);
			ctx.flush();
		}

		public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
			System.out.println("Transfer run handle channelRegistered");
			super.channelRegistered(ctx);
		}

		public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
			System.out.println("Transfer run handle channelUnregistered");
			super.channelUnregistered(ctx);
		}

		public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
			System.out.println("Transfer run handle channelWritabilityChanged");
			super.channelWritabilityChanged(ctx);
		}
	}

	public static class InitHandle extends ChannelInitializer {
		public InitHandle() {
		}

		protected void initChannel(Channel arg0) throws Exception {
			System.out.println("init");
		}
	}

	public static String toHexString(byte[] aBytes) {
		return toHexString(aBytes, 0, aBytes.length);
	}

	public static String toHexString(byte[] aBytes, int aOffset, int aLength) {
		char[] dst = new char[aLength * 2];

		for (int si = aOffset, di = 0; si < aOffset + aLength; si++) {
			byte b = aBytes[si];
			dst[di++] = CHARS_TABLES[(b & 0xf0) >>> 4];
			dst[di++] = CHARS_TABLES[(b & 0x0f)];
		}

		return new String(dst);
	}
}